package motor;


import java.util.*;
import java.io.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
     
    // to run simply do a: new BC(ask,tell) and then bc.execute()
    // ask is a propositional symbol
    // and tell is a knowledge base
    // ask : p
    // tell : p=>q;q=>r;r;

/**
 *
 * @author ariel.pilone
 */
public class IterativoReglas {
    
    
    
    private Connection conexion;
    private Statement instruccion;
    private ResultSet resulSet;    
        
        
    // create variables
    public static String tell;
    public static String ask;
    public static ArrayList<String> objetos;
    public static ArrayList<String> facts;
    public static ArrayList<String> reglas;
    public static ArrayList<String> implicados;

    public IterativoReglas(String a) throws SQLException{
    	this(a, null, null);
    }
    
    
    public IterativoReglas(String a, ArrayList<String> reglasResueltas, ArrayList<String> hechos) throws SQLException{
    // initialize variables
    objetos = new ArrayList<String>();
    if (reglas != null){
    	reglas = reglasResueltas;
    } else {
    	reglas = new ArrayList<String>();
    }
    implicados = new ArrayList<String>();
    if (hechos != null){
    	facts = hechos;
    } else {
    	facts = new ArrayList<String>();    	
    }
   
    ask = a;
    init();
    }
    
        public void cargar_hechos() throws SQLException{
       String  query="select * from hecho  ;";
     
       System.out.println("Hechos cargados: " );

            resulSet = this.instruccion.executeQuery(query) ;
String fac;
            while(resulSet.next()){
              /*  Hecho hecho=new Hecho();
                hecho.hec_id=resulSet.getInt(1);
                hecho.hho_descripcion=resulSet.getString(2);*/
             fac=resulSet.getString(2);
                facts.add(fac);
                
      //     System.out.println(fac);
                
            }
        
       try {
            this.resulSet.close();
            this.instruccion.close();
        } catch (SQLException ex) {
   //         Logger.getLogger(Confirmar_pago.class.getName()).log(Level.SEVERE, null, ex);
        }
    }    
      
    
    public void cargar_reglas() throws SQLException{
       String  query="select * from reglas  ;";
       /* como en el ejemplo usa por ej a&b => C lo dejo en el formato q estaba ademas quedar mejor*/
      
            resulSet = this.instruccion.executeQuery(query) ;

            while(resulSet.next()){
                Regla reg=new Regla();
                reg.id=resulSet.getInt(1);
                reg.ant=resulSet.getString(2);
                reg.ant1=resulSet.getString(3);
                reg.cons=resulSet.getString(4);
                reg.union=resulSet.getString(5);
                
                 String regla_String = new String();
          
               if(reg.ant!=null) 
                    regla_String+=reg.ant;
                if(reg.ant1!=null) 
                    regla_String+="&"+reg.ant1;
                
               if(reg.cons!=null)
                   regla_String+="=>"+reg.cons;
                
                reglas.add(regla_String);
                
       /*     System.out.println(reg.id+" - "+reg.ant+" - "+reg.ant1+" - "+reg.cons+" - "+reg.union+" - "+reg.usada);
              System.out.println("Regla String");
              System.out.println(regla_String);*/
                
            }
              
    }
    
        public void conectarBase(){
    	String url_base = "jdbc:postgresql://localhost:5432/tpfinal";
    	String usuario_base="postgres";
    	String pass_base="postgres";
    	
    	/*	System.out.println("Base= "+url_base+" usu= "+usuario_base+" pass= "+pass_base);*/
    	
		try{
	        Class.forName("org.postgresql.Driver").newInstance();
	  	    this.conexion = DriverManager.getConnection (url_base, usuario_base, pass_base);
            instruccion =  this.conexion.createStatement();
		}catch(ClassNotFoundException e){
			System.err.println("NOOOO'conectarAccess()' Error al intentar cargar Driver.NOOOOOO "+e.getMessage());
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

    // method which sets up initial values for backward chaining
    public  void init() throws SQLException{
    	objetos.add(ask);  
        conectarBase();
        if (reglas.isEmpty()){
        	cargar_reglas();
        }
        if (facts.isEmpty()){
        	cargar_hechos();
        }
    }
     
    // method which calls the main bcentails() method and returns output back to iengine
    public String execute(){
    String output = "";
     
    if (bcentails()){
    // the method returned true so it entails
    output = "YES: ";
    // loop through all implicados symbols in reverse
    for (int i=implicados.size()-1;i>=0;i--){
    if (i==0)
    output += implicados.get(i);
    else	
    // no comma at the end
    output += implicados.get(i)+", ";
     
    }
    }
    // no
    else{
    output = "NO";
    }
    return output;
    }
     
    // method which runs the bc algorithm
public boolean bcentails(){
    // while the list of symbols are not empty
    while(!objetos.isEmpty()){
        // get current symbol
        String q = objetos.remove(objetos.size()-1);
        // add the implicados array
        implicados.add(q);

        // if this element is a fact then we dont need to go further
        if (!facts.contains(q)){
            // .. but it isnt so..
            // create array to hold new symbols to be processed
            ArrayList<String> p = new ArrayList<String>();
            for(int i=0;i<reglas.size();i++){
                // for each clause..
                if (conclusionContains(reglas.get(i),q)){
                    // that contains the symbol as its conclusion

                    ArrayList<String> temp = getPremises(reglas.get(i));
                    for(int j=0;j<temp.size();j++){
                    // add the symbols to a temp array
                    p.add(temp.get(j));
                    }
                }	
            }
            // no symbols were generated and since it isnt a fact either
            // then this sybmol and eventually ASK cannot be implied by TELL
            if (p.size()==0){
                return false;
            }
            else{
                // there are symbols so check for previously processed ones and add to objetos
                for(int i=0;i<p.size();i++){
                if (!implicados.contains(p.get(i)))
                objetos.add(p.get(i));
                }


            }
        }

    }//while end
    return true;
    }
     
    // methid that returns the conjuncts contained in a clause
    public static ArrayList<String> getPremises(String clause){
    // get the premise
    String premise = clause.split("=>")[0];
    ArrayList<String> temp = new ArrayList<String>();
    String[] conjuncts = premise.split("&");
    // for each conjunct
    for(int i=0;i<conjuncts.length;i++){
    if (!objetos.contains(conjuncts[i]))
    temp.add(conjuncts[i]);
    }
    return temp;
    }
     
     
    // method which checks if c appears in the conclusion of a given clause
    // input : clause, c
    // output : true if c is in the conclusion of clause
    public static boolean conclusionContains(String clause, String c){
    String conclusion = clause.split("=>")[1];
    if (conclusion.equals(c))
    return true;
    else
    return false;
     
    }
    
}
